﻿using NetworkLib;
using NetworkLib.Utilities;
using PBO.Network.Domain;
using PBO.Network.Old;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace PBO.Network.Proxy
{
    public class BattleAgentServer : BattleServer
    {
        private int _battleIdentityBase = -1;
        private Dictionary<int, BattleAgent> _agents = new Dictionary<int, BattleAgent>();

        public BattleAgentServer()
            : base((int)ServerPort.BattleAgentServerPort)
        {
            this.UpdateInterval = 500;
            this.OnLogicUpdate += BattleAgentServer_OnLogicUpdate;
            this.OnClientDisconnected += BattleAgentServer_OnClientDisconnected;
        }

        void BattleAgentServer_OnClientDisconnected(ClientSession client)
        {
            var session = client as BattleAgentSession;

            if (session.AgentID != -1)
            {
                BattleAgent agent = GetAgent(session.AgentID);
                if (agent != null && !agent.BattleEnd)
                {
                    agent.PlayerExit(client.SessionID);
                }
            }
        }

        void BattleAgentServer_OnLogicUpdate()
        {
            var keys = _agents.Where(t => t.Value.BattleEnd).Select(t => t.Key).ToArray();
            foreach (int key in keys)
            {
                _agents.Remove(key);
                Logger.LogInfo("Remove battle agent, ID : {0}", key);
            }
        }

        protected override ClientSession CreateClientSession(int sessionID, IReactor reactor)
        {
            return new BattleAgentSession(sessionID, reactor, Buffered);
        }

        public int AddBattle(BattleMode mode, List<BattleRule> rules)
        {
            _battleIdentityBase++;
            BattleAgent agent = new BattleAgent(mode, rules, this);
            _agents[_battleIdentityBase] = agent;

            Logger.LogInfo("Add battle agent, ID : {0}", _battleIdentityBase);
            return _battleIdentityBase;
        }

        #region send

        public void SendTeam(int sessionID, byte position, string identity, List<byte> byteSequence)
        {
            var rsp = new UserInfo();
            rsp.position = position;
            rsp.identity = identity;
            rsp.team = byteSequence;
            base.SendData(sessionID, (int)EnumPokemonBattleMethods.Client_ReceiveTeam_Hash, rsp);
        }

        public void SendMove(int sessionID, PlayerMove move)
        {
            base.SendData(sessionID, (int)EnumPokemonBattleMethods.Client_ReceiveMove_Hash, move);
        }

        public void SendExitMessage(int sessionID, string identity)
        {
            base.SendData(sessionID, (int)EnumPokemonBattleMethods.Client_Exit_Hash, identity);
        }

        public void SendTieMessage(int sessionID, string identity, TieMessage message)
        {
            var rsp = new TieMessageResponse();
            rsp.identity = identity;
            rsp.message = message;
            base.SendData(sessionID, (int)EnumPokemonBattleMethods.Client_ReceiveTieMessage_Hash, rsp);
        }

        public void SendBattleData(int sessionID, List<BattleRule> rules, int randomSeed)
        {
            base.SendData(sessionID, (int)EnumPokemonBattleMethods.Client_ReceiveRules_Hash, rules);
            base.SendData(sessionID, (int)EnumPokemonBattleMethods.Client_ReceiveRandomSeed_Hash, randomSeed);
        }

        public void SendBattleSnapshot(int sessionID, BattleSnapshot snapshot)
        {
            base.SendData(sessionID, (int)EnumPokemonBattleMethods.Client_ReceiveBattleSnapshot_Hash, snapshot);
        }

        public void SendBattleInfo(int sessionID, BattleInfo info)
        {
            base.SendData(sessionID, (int)EnumPokemonBattleMethods.Client_ReceiveBattleInfo_Hash, info);
        }

        public void RegistObserver(int sessionID)
        {
            base.SendData(sessionID, (int)EnumPokemonBattleMethods.Client_RegistObsever_Hash, 0);
        }

        public void PlayerTimeUp(int sessionID, string identity)
        {
            base.SendData(sessionID, (int)EnumPokemonBattleMethods.Client_TimeUp_Hash, identity);
        }

        #endregion

        private BattleAgent GetAgent(int agentID)
        {
            BattleAgent agent;
            bool contains = _agents.TryGetValue(agentID, out agent);
            if (contains) return agent;
            return null;
        }

        private BattleAgent GetClientAgent(int sessionID)
        {
            ClientSession client = GetClient(sessionID);
            if (client == null || (client as BattleAgentSession).AgentID == -1) return null;
            return GetAgent((client as BattleAgentSession).AgentID);
        }

        #region IPokemonBattleServerService 成员

        public void OnLogon(int sessionID, string identity, BattleMode modeInfo, string versionInfo)
        {
            int agentId;
            BattleAgent agent = null;
            if (int.TryParse(identity, out agentId))
            {
                agent = GetAgent(agentId);
            }
            if (agent != null)
            {
                if (!agent.BattleEnd)
                {
                    (GetClient(sessionID) as BattleAgentSession).AgentID = agentId;
                    agent.UserLogon(sessionID, identity);
                    SendData(sessionID, (int)EnumPokemonBattleMethods.Client_LogonSuccess_Hash, string.Empty);
                }
                else
                {
                    SendData(sessionID, (int)EnumPokemonBattleMethods.Client_LogonFail_Hash, "对手已退出");
                    Disconnect(sessionID);
                }
            }
            else
            {
                SendData(sessionID, (int)EnumPokemonBattleMethods.Client_LogonFail_Hash, "无法找到对应的对战代理");
                Disconnect(sessionID);
            }
        }

        public void OnReceiveMove(int sessionID, PlayerMove move)
        {
            BattleAgent agent = GetClientAgent(sessionID);
            if (agent != null)
            {
                agent.ReceiveMove(sessionID, move);
            }
        }

        public void OnReceiveTeam(int sessionID, byte position, string identity, List<byte> team)
        {
            BattleAgent agent = GetClientAgent(sessionID);
            if (agent != null)
            {
                agent.ReceiveTeam(sessionID, position, identity, team);
            }
        }

        public void OnExit(int sessionID, string identity)
        {
            Disconnect(sessionID);
        }

        public void OnReceiveTieMessage(int sessionID, string identity, TieMessage message)
        {
            BattleAgent agent = GetClientAgent(sessionID);
            if (agent != null)
            {
                agent.ReceiveTieMessage(sessionID, message);
            }
        }

        public void OnRegistObsever(int sessionID, int identity)
        {
            BattleAgent agent = GetAgent(identity);
            if (agent != null && !agent.BattleEnd)
            {
                agent.RegistObserver(sessionID);
            }
        }

        public void OnReceiveBattleInfo(int sessionID, BattleInfo info)
        {
            BattleAgent agent = GetClientAgent(sessionID);
            if (agent != null)
            {
                agent.ReceiveBattleInfo(info);
            }
        }

        public void OnReceiveBattleSnapshot(int sessionID, BattleSnapshot snapshot)
        {
            BattleAgent agent = GetClientAgent(sessionID);
            if (agent != null)
            {
                agent.ReceiveBattleSnapshot(snapshot);
            }
        }

        public void OnTimeUp(int sessionID, string identity)
        {
            BattleAgent agent = GetClientAgent(sessionID);
            if (agent != null)
            {
                agent.PlayerTimeUp(sessionID, identity);
            }
        }
        #endregion

        protected override void OnReceiveData(int sessionID, int method, string json)
        {
            base.OnReceiveData(sessionID, method, json);
            switch ((EnumPokemonBattleMethods)method)
            {
                case EnumPokemonBattleMethods.Server_Logon_Hash:
                    var logon = StringUtils.ParseResponse<LogonResponse>(json);
                    OnLogon(sessionID, logon.identity, logon.modeInfo, logon.versionInfo);
                    break;
                case EnumPokemonBattleMethods.Server_ReceiveMove_Hash:
                    OnReceiveMove(sessionID, StringUtils.ParseResponse<PlayerMove>(json));
                    break;
                case EnumPokemonBattleMethods.Server_ReceiveTeam_Hash:
                    var team = StringUtils.ParseResponse<UserInfo>(json);
                    OnReceiveTeam(sessionID, team.position, team.identity, team.team);
                    break;
                case EnumPokemonBattleMethods.Server_Exit_Hash:
                    OnExit(sessionID, json);
                    break;
                case EnumPokemonBattleMethods.Server_TimeUp_Hash:
                    OnTimeUp(sessionID, json);
                    break;
                case EnumPokemonBattleMethods.Server_ReceiveTieMessage_Hash:
                    var tie = StringUtils.ParseResponse<TieMessageResponse>(json);
                    OnReceiveTieMessage(sessionID, tie.identity, tie.message);
                    break;
                case EnumPokemonBattleMethods.Server_RegistObsever_Hash:
                    OnRegistObsever(sessionID, int.Parse(json));
                    break;
                case EnumPokemonBattleMethods.Server_ReceiveBattleInfo_Hash:
                    OnReceiveBattleInfo(sessionID, StringUtils.ParseResponse<BattleInfo>(json));
                    break;
                case EnumPokemonBattleMethods.Server_ReceiveBattleSnapshot_Hash:
                    OnReceiveBattleSnapshot(sessionID, StringUtils.ParseResponse<BattleSnapshot>(json));
                    break;
            }
        }
    }
}
